#pragma once
#ifndef OBR_SCENE_H
#define OBR_SCENE_H

#include "Compute/PostProcess.h"
#include "Renderer.h"
#include "VirtualProgramManager.h"
#include "common.h"

namespace OBR
{
class Scene
{
    /* data */
public:
    Spectrum *result = nullptr;
    CudaBuffer d_result;
    Params params;
    std::shared_ptr<Camera> camera;
    std::shared_ptr<Background> background;
    std::shared_ptr<ASNode> rootAS;
    std::shared_ptr<Integrator> integrator;
    VirtualProgramManager lights;
    VirtualProgramManager materials;
    VirtualProgramManager mediums;
    VirtualProgramManager meshes;
    std::vector<std::shared_ptr<Instance>> instances;
    bool has_update = false;
    size_t acc_sample_cnt = 0;
    size_t target_spp = 0;

    bool enable_accumulate = false;

private:
    Renderer renderer;
    size_t frame_idx = 0;
    CudaBuffer d_light_desc;

    /* methods */
public:
    Scene();
    ~Scene();
    /**
     * @brief SET or UPDATE the Camera object
     *
     * @param bg new background object
     */
    void setBackground(std::shared_ptr<Background> bg);
    /**
     * @brief SET or UPDATE the Camera object
     *
     * @param cam new camera obj
     */
    void setCamera(std::shared_ptr<Camera> cam);
    /**
     * @brief SET or UPDATE the Camera object
     *
     * @param cam new camera obj
     */
    void setIntegrator(std::shared_ptr<Integrator> integrator);
    /**
     * @brief setup launch params
     *
     * @param params
     */
    void setupLaunchParams();
    /**
     * @brief setup renderer object and bind all states in optix
     *
     */
    void setupRenderer();

    /**
     * @brief draw next frame and store to fbo
     *
     */
    void renderFrame();

    /**
     * @brief download results
     *
     */
    void downloadResult();

private:
    void postprocess();

private:
};

} // namespace OBR

#endif